﻿/// <summary>
/// Developer: CHOOI KAH WAI
/// Last Modified: 21/11/2009
/// </summary>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Win32;
using ARSS.Editor.Common;
using System.IO;
using System.Windows.Markup;
using System.Windows.Media.Media3D;
using _3DTools;
using System.Diagnostics;
using System.Xml.Linq;
using ARSS.Common;
using System.Collections.ObjectModel;

namespace ARSS.Editor.Visual
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class PreviewWindow : Window
    {
        #region Functions

        /// <summary>
        /// Constructor
        /// </summary>
        public PreviewWindow()
        {
            InitializeComponent();

            Loaded += new RoutedEventHandler(PreviewWindow_Loaded);
        }

        /// <summary>
        /// Window loaded event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void PreviewWindow_Loaded(object sender, RoutedEventArgs e)
        {
            EditorMenu.IsEnabled = false;
            FileMenu_Save.IsEnabled = false;

            // Setup origin lines
            SetOriginLineLength(10000);
        }

        /// <summary>
        /// FileMenu.Exit Click Event Handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FileMenu_Exit_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// EditorMenu.SceneNodes Click Event Handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void EditorMenu_SceneNodes_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            Core.Instance.ShowSceneNodesWindow();
        }

        /// <summary>
        /// EditorMenu.Animation Click Event Handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void EditorMenu_Animation_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            Core.Instance.ShowAnimationWindow();
        }

        /// <summary>
        /// FileMenu.Open Click Event Handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FileMenu_Open_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Filter = "XML documents |*.xml";

            Nullable<bool> result = dialog.ShowDialog();

            if (result == true)
            {
                Core.Instance.ScenePath = dialog.FileName;
                Core.Instance.LoadScene();

                EditorMenu.IsEnabled = true;
                FileMenu_Save.IsEnabled = true;
            }
        }

        /// <summary>
        /// Load the scene node models
        /// </summary>
        /// <param name="node">Scene node</param>
        /// <param name="parent">Parent model visual 3d</param>
        public void PrepareSceneNode(SceneNode node, ModelVisual3D parent)
        {
            FileStream fs = new FileStream(System.IO.Path.GetDirectoryName(
                        Process.GetCurrentProcess().MainModule.FileName) + "\\" + node.ModelPath, FileMode.Open);
            node.Model3D = (ModelVisual3D)XamlReader.Load(fs);
            fs.Close();

            // Load transformation
            Transform3DGroup tg = new Transform3DGroup();

            // Rotation
            tg.Children.Add(new RotateTransform3D(
                                                    new AxisAngleRotation3D(new Vector3D(1, 0, 0), node.Rotation.X)));
            tg.Children.Add(new RotateTransform3D(
                                                    new AxisAngleRotation3D(new Vector3D(0, 1, 0), node.Rotation.Y)));
            tg.Children.Add(new RotateTransform3D(
                                                    new AxisAngleRotation3D(new Vector3D(0, 0, 1), node.Rotation.Z)));

            // Scale
            tg.Children.Add(new ScaleTransform3D(node.Scale));

            // Translation
            tg.Children.Add(new TranslateTransform3D(node.Translation));

            node.Model3D.Transform = tg;

            parent.Children.Add(node.Model3D);

            // Load its children
            foreach (SceneNode child in node.Children)
            {
                PrepareSceneNode(child, node.Model3D);
            }
        }

        /// <summary>
        /// Window resized
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_SizeChanged(object sender, System.Windows.SizeChangedEventArgs e)
        {
            MainViewPort.Width = e.NewSize.Width;
            MainViewPort.Height = e.NewSize.Height;
        }

        /// <summary>
        /// Reload the scene
        /// </summary>
        public void ReloadScene()
        {
            // Clear previous scene nodes, leave the origin lines
            while (ModelContainer.Children.Count > 3)
                ModelContainer.Children.RemoveAt(3);

            PrepareSceneNode(Core.Instance.SceneData.Root, ModelContainer);
        }

        /// <summary>
        /// Set the origin lines' length
        /// </summary>
        /// <param name="length"></param>
        public void SetOriginLineLength(double length)
        {
            OriginX.Points[1] = new Point3D(length, 0, 0);
            OriginY.Points[1] = new Point3D(0, length, 0);
            OriginZ.Points[1] = new Point3D(0, 0, length);
        }

        /// <summary>
        /// Window closing event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            Core.Instance.Close();
        }

        /// <summary>
        /// FileMenu.Save Event Handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FileMenu_Save_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            XDocument doc = new XDocument();

            SceneDef sceneData = Core.Instance.SceneData;

            // Scene Node
            XElement sceneElement = new XElement("Scene");
            sceneElement.Add(new XAttribute("title", sceneData.Title));
            sceneElement.Add(new XAttribute("boardPath", sceneData.BoardPath));
            sceneElement.Add(new XAttribute("actionsPath", sceneData.ActionsPath));
            
            //
            XElement rootElement = new XElement("Root");
            SaveSceneNode(sceneData.Root, rootElement);
            sceneElement.Add(rootElement);

            // Animations
            XElement animationsElement = new XElement("Animations");
            SaveAnimations(animationsElement);
            sceneElement.Add(animationsElement);

            // Actions
            XElement actionsElement = new XElement("Actions");
            SaveActions(actionsElement);
            sceneElement.Add(actionsElement);

            //
            SaveFileDialog dialog = new SaveFileDialog();
            dialog.Filter = "XML documents |*.xml";

            Nullable<bool> result = dialog.ShowDialog();

            if (result == true)
            {
                doc.Add(sceneElement);
                doc.Save(dialog.FileName);

                MessageBox.Show("File saved.");
            }
        }

        /// <summary>
        /// Save actions
        /// </summary>
        /// <param name="actionsElement"></param>
        private void SaveActions(XElement actionsElement)
        {
            // Fixed to 1 locker
            XElement actElement = new XElement("Act");
            actElement.Add(new XAttribute("model", "data/Model/Locker.xaml"));
            actElement.Add(new XAttribute("arCode", "0"));
            actElement.Add(new XAttribute("actionCode", "1"));
            actElement.Add(new XAttribute("name", "Locker_1"));

            actionsElement.Add(actElement);
        }

        /// <summary>
        /// Save Animations
        /// </summary>
        private void SaveAnimations(XElement animationsElement)
        {
            foreach (KeyValuePair<string, ObservableCollection<KeyFrame>> item in Core.Instance.SceneData.Animations)
            {
                XElement setElement = new XElement("Set");
                setElement.Add(new XAttribute("name", item.Key));

                foreach (KeyFrame kf in item.Value)
                {
                    XElement keyFrameElement = new XElement("KeyFrame");
                    keyFrameElement.Add(new XAttribute("tsec", kf.TSec.ToString("0.00")));
                    foreach (AnimationNode animNode in kf.Nodes)
                    {
                        XElement animElement = new XElement("AnimationNode");
                        animElement.Add(new XAttribute("target", animNode.Target));
                        animElement.Add(new XAttribute("x", animNode.X));
                        animElement.Add(new XAttribute("y", animNode.Y));
                        animElement.Add(new XAttribute("z", animNode.Z));
                        keyFrameElement.Add(animElement);
                    }
                    setElement.Add(keyFrameElement);
                }
                animationsElement.Add(setElement);
            }
        }

        /// <summary>
        /// Save scene node
        /// </summary>
        /// <param name="sceneNode"></param>
        /// <param name="nodeElement"></param>
        private void SaveSceneNode(SceneNode sceneNode, XElement nodeElement)
        {
            nodeElement.Add(new XAttribute("model", sceneNode.ModelPath));
            nodeElement.Add(new XAttribute("name", sceneNode.Name));

            XElement scaleElement = new XElement("Scale");
            scaleElement.Add(new XAttribute("x", sceneNode.Scale.X.ToString()));
            scaleElement.Add(new XAttribute("y", sceneNode.Scale.Y.ToString()));
            scaleElement.Add(new XAttribute("z", sceneNode.Scale.Z.ToString()));
            nodeElement.Add(scaleElement);

            XElement translateElement = new XElement("Translate");
            translateElement.Add(new XAttribute("x", sceneNode.Translation.X.ToString()));
            translateElement.Add(new XAttribute("y", sceneNode.Translation.Y.ToString()));
            translateElement.Add(new XAttribute("z", sceneNode.Translation.Z.ToString()));
            nodeElement.Add(translateElement);

            XElement rotateElement = new XElement("Rotate");
            rotateElement.Add(new XAttribute("x", sceneNode.Rotation.X.ToString()));
            rotateElement.Add(new XAttribute("y", sceneNode.Rotation.Y.ToString()));
            rotateElement.Add(new XAttribute("z", sceneNode.Rotation.Z.ToString()));
            nodeElement.Add(rotateElement);

            // Write its children
            XElement childrenElement = new XElement("Children");
            foreach (SceneNode childNode in sceneNode.Children)
            {
                XElement childElement = new XElement("Child");
                SaveSceneNode(childNode, childElement);
                childrenElement.Add(childElement);
            }

            nodeElement.Add(childrenElement);
        }

        /// <summary>
        /// FileMenu.New Event Handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FileMenu_New_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            EditorMenu.IsEnabled = true;
            FileMenu_Save.IsEnabled = true;

            while (ModelContainer.Children.Count > 3)
                ModelContainer.Children.RemoveAt(3);

            Core.Instance.SceneData = new ARSS.Common.SceneDef();
            Core.Instance.SceneData.Root = new SceneNode();
            Core.Instance.SceneData.Root.Name = "Root";

        }

        /// <summary>
        /// EditorMenu.SceneSettings Event Handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void EditorMenu_SceneSettings_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            Core.Instance.ShowSceneSettingsWindow();
        }

        

        #endregion
    }
}
